#ifndef GX_FR_LIGHTMAP_H
#define GX_FR_LIGHTMAP_H

#include "Basic/GxLibBasic.h"
#include "BSP_Scene.h"
#include "Shader.h"
#include "Cubemap.h"

namespace FinalRendering
{
	namespace Engine
	{
		using namespace GxLibBasic;
		class Lightmap : public Object
		{
		private:
			int width, height;
			UInt handle;
		public:
			Lightmap(int _width, int _height, bool clear = false);
			~Lightmap();
			void SetFilter(bool linear);
			UInt GetHandle();
			int GetArea();
			void CopyImage(Array<float> & buffer);
			void Load(Stream * stream);
			void Save(Stream * stream);
			void SetImage(Array<float> & buffer);
			int GetWidth();
			int GetHeight();
			void SetSize(int nw, int nh);
		};

		class LightmapErrorException
		{};

		class LightmapSolution : public Object
		{
			friend class LightmapDirectIlluminationGenerator;
		/*
			B = {-1/sqrt(6), 1/sqrt(2), 1/sqrt(3)},
				{-1/sqrt(6), -1/sqrt(2), 1/sqrt(3)},
				{sqrt(2/3), 0, 1/sqrt(3)}
		*/
		private:
			RefPtr<Program> progLight;
			Scene * scene;
			vec3 curLightPos;
			Array<RefPtr<Lightmap>> lightmaps[3];
			Array<RefPtr<Lightmap>> diffuseMaps;
			void GenerateDirectIllumination(Array<RefPtr<Lightmap>> *lightmaps);
			void GenerateDirectIlluminationNonBump(Array<RefPtr<Lightmap>> &lightmaps);
			void GenerateRadiosity();
			void DrawNode(BSP_Node & node);
			void GenerateDiffuseMaps(Array<RefPtr<Lightmap>> & lightmaps);
			void BlendRadiosity(Array<RefPtr<Lightmap>> * lmRads);
			void ChangeStatus(String s1, String s2);
			void ChangeProgress(int val, int max);
		public:
			bool ComputeRadiosity;
			float RadiosityThreshold;
			float PatchSize;
			LightmapSolution(Scene * _scene);
			void Generate();
			void Merge();
			void RenderScene();
			void Load(Stream * stream);
			void Save(Stream * stream);
			void Load(const String & fileName);
			void Save(const String & fileName);
			void BindLightmap(int id);
			void UnBindLightmap();
			int GetMapCount();
			Lightmap * GetLightmap(int id, int axis = 0);
			Lightmap * GetDiffuseMap(int id);
			Event<int> BindDiffuseTexture;
			Event<float> PassFinished;
			Event<String, String> StatusChanged;
			Event<int, int> ProgressChanged;
		};
	}
}

#endif